package org.xbill.DNS;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class Message
  implements Cloneable
{
  public static final int MAXLENGTH = 65535;
  static final int TSIG_FAILED = 4;
  static final int TSIG_INTERMEDIATE = 2;
  static final int TSIG_SIGNED = 3;
  static final int TSIG_UNSIGNED = 0;
  static final int TSIG_VERIFIED = 1;
  private static RRset[] emptyRRsetArray;
  private static Record[] emptyRecordArray = new Record[0];
  private Header header;
  private TSIGRecord querytsig;
  private List[] sections;
  int sig0start;
  private int size;
  int tsigState;
  private int tsigerror;
  private TSIG tsigkey;
  int tsigstart;

  static
  {
    emptyRRsetArray = new RRset[0];
  }

  public Message()
  {
    this(new Header());
  }

  public Message(int paramInt)
  {
    this(new Header(paramInt));
  }

  Message(DNSInput paramDNSInput)
    throws IOException
  {
    this(new Header(paramDNSInput));
    if (this.header.getOpcode() == 5)
    {
      bool1 = true;
      bool2 = this.header.getFlag(6);
      i = 0;
    }
    while (true)
    {
      int j;
      int k;
      while (i >= 4)
      {
        this.size = paramDNSInput.current();
        return;
        bool1 = false;
      }
      do
      {
        try
        {
          j = this.header.getCount(i);
          if (j > 0)
          {
            Object localObject;
            this.sections[i] = new ArrayList(j);
            break label182:
            int l = paramDNSInput.current();
            Record localRecord = Record.fromWire(paramDNSInput, i, bool1);
            this.sections[i].add(localRecord);
            if (localRecord.getType() == 250)
              this.tsigstart = l;
            if ((localRecord.getType() == 24) && (((SIGRecord)localRecord).getTypeCovered() == 0))
              this.sig0start = l;
            ++localObject;
          }
        }
        catch (WireParseException localWireParseException)
        {
          if (bool2);
          throw localWireParseException;
        }
        label182: k = 0;
      }
      while (k < j);
      ++i;
    }
  }

  private Message(Header paramHeader)
  {
    this.sections = new List[4];
    this.header = paramHeader;
  }

  public Message(byte[] paramArrayOfByte)
    throws IOException
  {
    this(new DNSInput(paramArrayOfByte));
  }

  public static Message newQuery(Record paramRecord)
  {
    Message localMessage = new Message();
    localMessage.header.setOpcode(0);
    localMessage.header.setFlag(7);
    localMessage.addRecord(paramRecord, 0);
    return localMessage;
  }

  public static Message newUpdate(Name paramName)
  {
    return new Update(paramName);
  }

  private static boolean sameSet(Record paramRecord1, Record paramRecord2)
  {
    int i;
    if ((paramRecord1.getRRsetType() == paramRecord2.getRRsetType()) && (paramRecord1.getDClass() == paramRecord2.getDClass()) && (paramRecord1.getName().equals(paramRecord2.getName())))
      i = 1;
    while (true)
    {
      return i;
      i = 0;
    }
  }

  private int sectionToWire(DNSOutput paramDNSOutput, int paramInt1, Compression paramCompression, int paramInt2)
  {
    int i = this.sections[paramInt1].size();
    int j = paramDNSOutput.current();
    int k = 0;
    Object localObject = null;
    int l = 0;
    while (true)
    {
      int i1;
      if (l >= i)
        i1 = 0;
      while (true)
      {
        return i1;
        Record localRecord = (Record)this.sections[paramInt1].get(l);
        if ((localObject != null) && (!(sameSet(localRecord, (Record)localObject))))
        {
          j = paramDNSOutput.current();
          k = l;
        }
        localObject = localRecord;
        localRecord.toWire(paramDNSOutput, paramInt1, paramCompression);
        if (paramDNSOutput.current() <= paramInt2)
          break;
        paramDNSOutput.jump(j);
        i1 = i - k;
      }
      ++l;
    }
  }

  private boolean toWire(DNSOutput paramDNSOutput, int paramInt)
  {
    int l;
    int i2;
    if (paramInt < 12)
    {
      i2 = 0;
      return i2;
    }
    Header localHeader = null;
    int i = paramInt;
    if (this.tsigkey != null)
      i -= this.tsigkey.recordLength();
    int j = paramDNSOutput.current();
    this.header.toWire(paramDNSOutput);
    Compression localCompression = new Compression();
    int k = 0;
    if (k >= 4);
    do
    {
      while (true)
      {
        if (this.tsigkey != null)
        {
          TSIGRecord localTSIGRecord = this.tsigkey.generate(this, paramDNSOutput.toByteArray(), this.tsigerror, this.querytsig);
          if (localHeader == null)
            localHeader = (Header)this.header.clone();
          localTSIGRecord.toWire(paramDNSOutput, 3, localCompression);
          localHeader.incCount(3);
          paramDNSOutput.save();
          paramDNSOutput.jump(j);
          localHeader.toWire(paramDNSOutput);
          paramDNSOutput.restore();
        }
        i2 = 1;
      }
      if (this.sections[k] == null);
      do
      {
        while (true)
          ++k;
        l = sectionToWire(paramDNSOutput, k, localCompression, i);
      }
      while (l == 0);
    }
    while (k == 3);
    if (0 == 0)
      localHeader = (Header)this.header.clone();
    localHeader.setFlag(6);
    localHeader.setCount(k, localHeader.getCount(k) - l);
    int i1 = k + 1;
    while (true)
    {
      while (i1 >= 4)
      {
        paramDNSOutput.save();
        paramDNSOutput.jump(j);
        localHeader.toWire(paramDNSOutput);
        paramDNSOutput.restore();
      }
      localHeader.setCount(i1, 0);
      ++i1;
    }
  }

  public void addRecord(Record paramRecord, int paramInt)
  {
    if (this.sections[paramInt] == null)
      this.sections[paramInt] = new LinkedList();
    this.header.incCount(paramInt);
    this.sections[paramInt].add(paramRecord);
  }

  public Object clone()
  {
    Message localMessage = new Message();
    int i = 0;
    while (true)
    {
      if (i >= this.sections.length)
      {
        localMessage.header = ((Header)this.header.clone());
        localMessage.size = this.size;
        return localMessage;
      }
      if (this.sections[i] != null)
        localMessage.sections[i] = new LinkedList(this.sections[i]);
      ++i;
    }
  }

  public boolean findRRset(Name paramName, int paramInt)
  {
    int i;
    if ((!(findRRset(paramName, paramInt, 1))) && (!(findRRset(paramName, paramInt, 2))) && (!(findRRset(paramName, paramInt, 3))))
      i = 0;
    while (true)
    {
      return i;
      i = 1;
    }
  }

  public boolean findRRset(Name paramName, int paramInt1, int paramInt2)
  {
    int j;
    if (this.sections[paramInt2] == null)
    {
      j = 0;
      return j;
    }
    int i = 0;
    while (true)
    {
      while (true)
      {
        while (i >= this.sections[paramInt2].size())
          j = 0;
        Record localRecord = (Record)this.sections[paramInt2].get(i);
        if ((localRecord.getType() != paramInt1) || (!(paramName.equals(localRecord.getName()))))
          break;
        j = 1;
      }
      ++i;
    }
  }

  public boolean findRecord(Record paramRecord)
  {
    int i = 1;
    while (true)
    {
      int j;
      if (i > 3)
        j = 0;
      while (true)
      {
        return j;
        if ((this.sections[i] == null) || (!(this.sections[i].contains(paramRecord))))
          break;
        j = 1;
      }
      ++i;
    }
  }

  public boolean findRecord(Record paramRecord, int paramInt)
  {
    int i;
    if ((this.sections[paramInt] != null) && (this.sections[paramInt].contains(paramRecord)))
      i = 1;
    while (true)
    {
      return i;
      i = 0;
    }
  }

  public Header getHeader()
  {
    return this.header;
  }

  public OPTRecord getOPT()
  {
    Record[] arrayOfRecord = getSectionArray(3);
    int i = 0;
    while (true)
    {
      OPTRecord localOPTRecord;
      if (i >= arrayOfRecord.length)
        localOPTRecord = null;
      while (true)
      {
        return localOPTRecord;
        if (!(arrayOfRecord[i] instanceof OPTRecord))
          break;
        localOPTRecord = (OPTRecord)arrayOfRecord[i];
      }
      ++i;
    }
  }

  public Record getQuestion()
  {
    Record localRecord;
    List localList = this.sections[0];
    if ((localList == null) || (localList.size() == 0))
      localRecord = null;
    while (true)
    {
      return localRecord;
      localRecord = (Record)localList.get(0);
    }
  }

  public int getRcode()
  {
    int i = this.header.getRcode();
    OPTRecord localOPTRecord = getOPT();
    if (localOPTRecord != null)
      i += (localOPTRecord.getExtendedRcode() << 4);
    return i;
  }

  public Record[] getSectionArray(int paramInt)
  {
    Record[] arrayOfRecord;
    if (this.sections[paramInt] == null)
      arrayOfRecord = emptyRecordArray;
    while (true)
    {
      return arrayOfRecord;
      List localList = this.sections[paramInt];
      arrayOfRecord = (Record[])localList.toArray(new Record[localList.size()]);
    }
  }

  public RRset[] getSectionRRsets(int paramInt)
  {
    LinkedList localLinkedList;
    Record[] arrayOfRecord;
    HashSet localHashSet;
    int i;
    int k;
    RRset[] arrayOfRRset;
    if (this.sections[paramInt] == null)
      arrayOfRRset = emptyRRsetArray;
    while (true)
    {
      return arrayOfRRset;
      localLinkedList = new LinkedList();
      arrayOfRecord = getSectionArray(paramInt);
      localHashSet = new HashSet();
      i = 0;
      if (i < arrayOfRecord.length)
        break;
      arrayOfRRset = (RRset[])localLinkedList.toArray(new RRset[localLinkedList.size()]);
    }
    Name localName = arrayOfRecord[i].getName();
    int j = 1;
    if (localHashSet.contains(localName))
      k = localLinkedList.size() - 1;
    while (true)
    {
      if (k < 0);
      while (true)
      {
        while (true)
        {
          if (j != 0)
          {
            localLinkedList.add(new RRset(arrayOfRecord[i]));
            localHashSet.add(localName);
          }
          ++i;
        }
        RRset localRRset = (RRset)localLinkedList.get(k);
        if ((localRRset.getType() != arrayOfRecord[i].getRRsetType()) || (localRRset.getDClass() != arrayOfRecord[i].getDClass()) || (!(localRRset.getName().equals(localName))))
          break;
        localRRset.addRR(arrayOfRecord[i]);
        j = 0;
      }
      --k;
    }
  }

  public TSIGRecord getTSIG()
  {
    TSIGRecord localTSIGRecord;
    int i = this.header.getCount(3);
    if (i == 0)
      localTSIGRecord = null;
    while (true)
    {
      Record localRecord;
      while (true)
      {
        return localTSIGRecord;
        localRecord = (Record)this.sections[3].get(i - 1);
        if (localRecord.type == 250)
          break;
        localTSIGRecord = null;
      }
      localTSIGRecord = (TSIGRecord)localRecord;
    }
  }

  public boolean isSigned()
  {
    int i;
    if ((this.tsigState != 3) && (this.tsigState != 1) && (this.tsigState != 4))
      i = 0;
    while (true)
    {
      return i;
      i = 1;
    }
  }

  public boolean isVerified()
  {
    int i;
    if (this.tsigState == 1)
      i = 1;
    while (true)
    {
      return i;
      i = 0;
    }
  }

  public int numBytes()
  {
    return this.size;
  }

  public void removeAllRecords(int paramInt)
  {
    this.sections[paramInt] = null;
    this.header.setCount(paramInt, 0);
  }

  public boolean removeRecord(Record paramRecord, int paramInt)
  {
    int i;
    if ((this.sections[paramInt] != null) && (this.sections[paramInt].remove(paramRecord)))
    {
      this.header.decCount(paramInt);
      i = 1;
    }
    while (true)
    {
      return i;
      i = 0;
    }
  }

  public String sectionToString(int paramInt)
  {
    StringBuffer localStringBuffer;
    Record[] arrayOfRecord;
    int i;
    String str;
    if (paramInt > 3)
      str = null;
    while (true)
    {
      return str;
      localStringBuffer = new StringBuffer();
      arrayOfRecord = getSectionArray(paramInt);
      i = 0;
      if (i < arrayOfRecord.length)
        break;
      str = localStringBuffer.toString();
    }
    Record localRecord = arrayOfRecord[i];
    if (paramInt == 0)
    {
      localStringBuffer.append(";;\t" + localRecord.name);
      localStringBuffer.append(", type = " + Type.string(localRecord.type));
      localStringBuffer.append(", class = " + DClass.string(localRecord.dclass));
    }
    while (true)
    {
      while (true)
      {
        localStringBuffer.append("\n");
        ++i;
      }
      localStringBuffer.append(localRecord);
    }
  }

  public void setHeader(Header paramHeader)
  {
    this.header = paramHeader;
  }

  public void setTSIG(TSIG paramTSIG, int paramInt, TSIGRecord paramTSIGRecord)
  {
    this.tsigkey = paramTSIG;
    this.tsigerror = paramInt;
    this.querytsig = paramTSIGRecord;
  }

  public String toString()
  {
    int i;
    StringBuffer localStringBuffer = new StringBuffer();
    if (getOPT() != null)
    {
      localStringBuffer.append(this.header.toStringWithRcode(getRcode()) + "\n");
      if (isSigned())
      {
        localStringBuffer.append(";; TSIG ");
        if (!(isVerified()))
          break label161;
        localStringBuffer.append("ok");
      }
    }
    while (true)
    {
      while (true)
      {
        localStringBuffer.append('\n');
        i = 0;
        if (i < 4)
          break label172;
        localStringBuffer.append(";; Message size: " + numBytes() + " bytes");
        return localStringBuffer.toString();
        localStringBuffer.append(this.header + "\n");
      }
      label161: localStringBuffer.append("invalid");
    }
    if (this.header.getOpcode() != 5)
      label172: localStringBuffer.append(";; " + Section.longString(i) + ":\n");
    while (true)
    {
      while (true)
      {
        localStringBuffer.append(sectionToString(i) + "\n");
        ++i;
      }
      localStringBuffer.append(";; " + Section.updString(i) + ":\n");
    }
  }

  void toWire(DNSOutput paramDNSOutput)
  {
    this.header.toWire(paramDNSOutput);
    Compression localCompression = new Compression();
    int i = 0;
    while (true)
    {
      if (i >= 4)
        return;
      if (this.sections[i] != null)
        break;
      ++i;
    }
    int j = 0;
    while (true)
    {
      if (j >= this.sections[i].size());
      ((Record)this.sections[i].get(j)).toWire(paramDNSOutput, i, localCompression);
      ++j;
    }
  }

  public byte[] toWire()
  {
    DNSOutput localDNSOutput = new DNSOutput();
    toWire(localDNSOutput);
    this.size = localDNSOutput.current();
    return localDNSOutput.toByteArray();
  }

  public byte[] toWire(int paramInt)
  {
    DNSOutput localDNSOutput = new DNSOutput();
    toWire(localDNSOutput, paramInt);
    this.size = localDNSOutput.current();
    return localDNSOutput.toByteArray();
  }
}